//#include <func.h>
#include "head.h"

int downloadFile(task_t *pTask){
    //gets file1
    char *command = strtok(pTask->buf," ");//解析获取命令
    char *fileName = strtok(NULL," ");//解析获取文件名
    int length = strlen(fileName);
    
    //首先判断文件是否存在,文件存在是传输文件的必要条件！ 
    DIR *pdir = opendir(".");
    ERROR_CHECK(pdir, NULL, "open");
    struct dirent *pdirent;
    while ((pdirent = readdir(pdir)) != NULL) {
        if(!strcmp(pdirent->d_name, fileName)) {
            break;
        }
    }
    if ((pdirent = readdir(pdir)) == NULL) {
        puts("No such file or directory!");
        send(pTask->netFd, "No such file or directory!", 26, 0);
        return -1;
    }

    char pianyi[100]={0};
    recv(pTask->netFd,pianyi,100,0);//接收客户端发来的客户端本地文件的大小，也就是偏移量
    //服务端再把字符串类改回long类型
    long pianyilen=atoi(pianyi);//偏移量也有可能是0
    //printf("pianyilen = %d\n",pianyilen);

    train_t t;
    bzero(t.buf,sizeof(t.buf));
    t.dataLength = length;
    strcpy(t.buf,fileName);

    printf("length = %d,fileName = %s\n",length,fileName);
    
    int fd = open(fileName, O_RDWR);
    ERROR_CHECK(fd,-1,"open");
    // int ret = send(pTask->netFd,&t,sizeof(t.dataLength)+ t.dataLength,MSG_NOSIGNAL);//发送文件名
    // ERROR_CHECK(ret,-1,"send");
    //不再需要发送文件名，客户端自己获取
    //获取服务器文件总大小并发送
    struct stat statbuf;
    int ret = fstat(fd,&statbuf);//获取文件的总大小
    ERROR_CHECK(ret,-1,"fstat");
    t.dataLength = sizeof(statbuf.st_size);//把文件的大小装入小火车
    memcpy(t.buf,&statbuf.st_size,sizeof(statbuf.st_size));
    send(pTask->netFd,&t,sizeof(t.dataLength)+t.dataLength,MSG_NOSIGNAL);

    //对比进行判断
    long totalFileLen = statbuf.st_size;
    printf("pianyilen = %ld,totallen = %ld\n",pianyilen,totalFileLen);
    if (pianyilen < totalFileLen) {
        lseek(fd, pianyilen, SEEK_SET);
    }
    else {
        //printf("Recv success!\n");
        return 0;
    }

    char *p = (char *)mmap(NULL,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    ERROR_CHECK(p,MAP_FAILED,"mmap");
    off_t total = pianyilen;
    while(total < statbuf.st_size){
        if(statbuf.st_size - total < sizeof(t.buf)){
            //最后一次发送
            t.dataLength = statbuf.st_size-total;
        }
        else{
            t.dataLength = sizeof(t.buf);
        }
        memcpy(t.buf,p+total,t.dataLength);//把数据装入火车车厢
        int ret = send(pTask->netFd,&t,sizeof(t.dataLength)+t.dataLength,MSG_NOSIGNAL);
        ERROR_CHECK(ret,-1,"send");
        total += t.dataLength;
    }
    munmap(p,statbuf.st_size);
    t.dataLength = 0;
    send(pTask->netFd,&t,sizeof(t.dataLength),0);
    //发送终止
    close(fd);
}
int recvn(int netFd,void *p, int n){
    int total = 0;
    int ret;
    char *pTmp = (char *)p;
    while(total < n){
        ret = recv(netFd,pTmp+total,n-total,0);
        ERROR_CHECK(ret,-1,"recv");
        total+= ret;
    }
    return 0;
}
int uploadFile(task_t *pTask, virDir_t *preVd){
    int dataLength;
    char name[1024] = {0};
    int ret =recvn(pTask->netFd,&dataLength,sizeof(int));//先收火车头
    ERROR_CHECK(ret,-1,"recv");
    ret = recvn(pTask->netFd,name, dataLength);//再收文件名
    ERROR_CHECK(ret,-1,"recv");
    int fd = open(name, O_RDWR|O_CREAT, 0666);
    ERROR_CHECK(fd,-1,"open");
    
    //接收md5
    long md5Length;
    char upMd5[1024] = {0};
    ret =recvn(pTask->netFd,&md5Length,sizeof(int));//先收火车头
    ERROR_CHECK(ret,-1,"recv");
    ret = recvn(pTask->netFd,upMd5, md5Length);//再收文件名
    ERROR_CHECK(ret,-1,"recv");

    //计算本地文件md5,并发送
    train_t t;
    char localMd5[1024] = {0};
    getMd5(name, localMd5);
    bzero(t.buf,sizeof(t.buf));
    t.dataLength = strlen(localMd5);
    strcpy(t.buf,localMd5);
    send(pTask->netFd, &t, sizeof(t.dataLength)+ t.dataLength, MSG_NOSIGNAL);
    ERROR_CHECK(ret,-1,"send");

    //如果和接收到的相同则直接返回传输成功，即秒传
    if (!strcmp(localMd5, upMd5)) {
        //秒传
        printf("Upload success!\n");
        close(fd);
        return 0;
    }

    char buf[1024] = {0};
    long fileSize;
    recvn(pTask->netFd,&dataLength,sizeof(int));//先收火车头
    recvn(pTask->netFd,&fileSize,sizeof(fileSize));//再收文件长度
    printf("fileSize = %ld\n", fileSize);
    //ftruncate(fd,fileSize);
    off_t downSize = 0;
    off_t lastSize = 0;
    off_t slice = fileSize/1000;
    struct timeval begTime,endTime;
    gettimeofday(&begTime,NULL);
    while(1){
        ret = recvn(pTask->netFd,&dataLength,sizeof(int));//先收火车头
        ERROR_CHECK(ret,-1,"recv");
        if(dataLength==0){
            break;
        }
        if(dataLength != 1000){
            printf("dataLength = %d\n", dataLength);
        }
        ret = recvn(pTask->netFd,buf,dataLength);
        ERROR_CHECK(ret,-1,"recv");
        downSize += dataLength;
        if(downSize-lastSize > slice){
            printf("%5.2lf%s\r", 100.0*downSize/fileSize,"%");
            fflush(stdout);
            lastSize = downSize;
        }
        write(fd,buf,dataLength);
    }
    printf("100.00%s\n", "%");
    gettimeofday(&endTime,NULL);
    printf("total time = %ld\n", 1000000*(endTime.tv_sec-begTime.tv_sec) + endTime.tv_usec-begTime.tv_usec);
    close(fd);

    //将文件存至虚拟目录
    MYSQL *db = mysql_init(NULL);
    databaseInit(db);
    //先默认用户登录时已在自身用户所在“目录”下
    virDir_t *curVd = (virDir_t *)calloc(1, sizeof(virDir_t));
    // int fd = open(dirName, O_RDWR|O_CREAT|O_EXCL, 0666);
    // ERROR_CHECK(fd, -1, "open");
    //MD5为主键，不允许重复，所以应该使其不为空
    

    strcpy(curVd->name, name);
    strcpy(curVd->pre_id, preVd->id);
    //curVd->pre_id = preVd->id;
    char md5[1024] = {0};
    getMd5(name, md5);
    strcpy(curVd->md5, md5);
    strcpy(curVd->user, preVd->user);
    strcpy(curVd->isDelete, "N");
    strcpy(curVd->type, "f");

    char sql[1024] = "insert into directory (name,pre_id,md5,user,isDelete,type) values('";
    sqlSplice(sql, curVd);
    
    int qret = mysql_query(db, sql);
    SQL_ERROR_CHECK(db, qret, 0);
    mysql_close(db);
    return 0;
}

void usrConnectRecord(task_t myTask){
    time_t now = time(NULL);
    struct tm * pTm = localtime(&now); 
    syslog(LOG_INFO,"netFd=%d %s %02d%02d %02d:%02d:%02d\n",myTask.netFd,"connect time:",pTm->tm_mon+1,
    pTm->tm_mday,pTm->tm_hour,pTm->tm_min,pTm->tm_sec); 
}
void usrCommandRecord(task_t myTask){
    syslog(LOG_INFO,"netFd=%d %s %s\n",myTask.netFd,"command:",myTask.buf); 
}